#define DEBUG
#include <cstdio>

using namespace std;

const int maxn=100000, maxk=17;

int min(int a, int b) {
  return a<b ? a : b;
}

int max(int a, int b) {
  return a>b ? a : b;
}

class SegmentTree  {
public:
  int v[4*maxn+1], mark[4*maxn+1];

  void markDown(int o, int l, int r) {
    if (mark[o]) {
      if (l!=r) {
	mark[o*2]^=1, mark[o*2+1]^=1;
      }
      mark[o] = 0;
      v[o] = r-l+1-v[o];
    }
  }

  void change(int o, int l, int r, int tl, int tr) {
    markDown(o, l, r);
    if (l==tl && r==tr) {
      mark[o] ^= 1;
      markDown(o, l, r);
    } else {
      int mid=(l+r)/2;
      if (tl<=mid) {
	change(o*2, l, mid, max(tl, l), min(tr, mid));
      }
      if (tr>mid) {
	change(o*2+1, mid+1, r, max(tl, mid+1), min(tr, r));
      }
      markDown(o*2, l, mid), markDown(o*2+1, mid+1, r);
      v[o] = v[o*2]+v[o*2+1];
    }
  }

  int get(int o, int l, int r, int tl, int tr) {
    markDown(o, l, r);
    if (l==tl && r==tr) {
      return v[o];
    } else {
      int mid=(l+r)/2, ret=0;
      if (tl<=mid) {
	ret += get(o*2, l, mid, max(tl, l), min(tr, mid));
      }
      if (tr>mid) {
	ret += get(o*2+1, mid+1, r, max(tl, mid+1), min(tr, r));
      }
      return ret;
    }
  }
};

class Tree {
public:
  SegmentTree side, point;
  int n, m, ind[maxn+1], link[2*maxn+1], to[2*maxn+1], f[maxn+1][maxk+1], dep[maxn+2], size[maxn+1], bigson[maxn+1], top[maxn+1], dfn[maxn+1];
  bool color[maxn+1];

  void addSide(int u, int v) {
    m++;
    to[m] = v;
    link[m] = ind[u];
    ind[u] = m;
  }

  void dfs1(int o, int fa) {
    dep[o] = dep[fa]+1;
    size[o] = 1;
    bigson[o] = 0;
    for (int i=ind[o]; i; i=link[i]) {
      if (to[i]!=fa) {
	f[to[i]][0] = o;
	dfs1(to[i], o);
	size[o] += size[to[i]];
	if (size[to[i]]>size[bigson[o]]) {
	  bigson[o] = to[i];
	}
      }
    }
  }

  void dfs2(int o) {
    dfn[o] = ++dfn[0];
    if (bigson[o]) {
      top[bigson[o]] = top[o];
      dfs2(bigson[o]);
    }
    for (int i=ind[o]; i; i=link[i]) {
      if (to[i]!=f[o][0] && to[i]!=bigson[o]) {
	top[to[i]] = to[i];
	dfs2(to[i]);
      }
    }
  }

  void build() {
    dfs1(1, 0);
    dep[n+1] = n+1;
    top[1] = 1;
    dfs2(1);
    for (int j=1; j<=maxk; j++) {
      for (int i=1; i<=n; i++) {
	f[i][j] = f[f[i][j-1]][j-1];
      }
    }
  }

  void lca(int &u, int &v, int &a, int &b) {
    if (u==v) {
      a = b = n+1;
      return;
    }
    if (dep[u]<dep[v]) {
      int t;
      t = u, u = v, v = t;
    }
    a = u, b = v;
    for (int i=maxk; i>=0; i--) {
      if (dep[f[a][i]]>=dep[b] && f[a][i]!=b) {
	a = f[a][i];
      }
    }
    if (dep[a]!=dep[b]) {
      b = n+1;
      return;
    }
    for (int i=maxk; i>=0; i--) {
      if (f[a][i]!=f[b][i]) {
	a = f[a][i], b = f[b][i];
      }
    }
  }

  void change1(int o, int t) {
    for (; dep[top[o]]>=dep[t]; o=f[top[o]][0]) {
      side.change(1, 1, n, dfn[top[o]], dfn[o]);
    }
    if (dep[o]>=dep[t] && top[o]!=t) {
      side.change(1, 1, n, dfn[t], dfn[o]);
    }
  }

  void change2(int o, int t) {
    for (; dep[top[o]]>=dep[t]; o=f[top[o]][0]) {
      if (bigson[o]) {
	side.change(1, 1, n, dfn[bigson[o]], dfn[bigson[o]]);
      }
      point.change(1, 1, n, dfn[top[o]], dfn[o]);
      side.change(1, 1, n, dfn[top[o]], dfn[top[o]]);
    }
    if (dep[o]>=dep[t] && top[o]!=t) {
      if (bigson[o]) {
	side.change(1, 1, n, dfn[bigson[o]], dfn[bigson[o]]);
      }
      point.change(1, 1, n, dfn[t], dfn[o]);
    }
  }

  int solve(int o, int t) {
    int ret=0;
    for (; dep[top[o]]>=dep[t]; o=f[top[o]][0]) {
      if (top[o]!=o) {
	ret += side.get(1, 1, n, dfn[bigson[top[o]]], dfn[o]);
      }
      ret += side.get(1, 1, n, dfn[top[o]], dfn[top[o]])^point.get(1, 1, n, dfn[f[top[o]][0]], dfn[f[top[o]][0]]);
    }
    if (dep[o]>=dep[t] && top[o]!=t) {
      ret += side.get(1, 1, n, dfn[t], dfn[o]);
    }
    return ret;
  }
};

int main() {
#ifdef DEBUG
  freopen("src.in", "r", stdin);
  freopen("src.out", "w", stdout);
#endif

  static Tree tree;
  int n;
  scanf("%d", &n);
  tree.n = n;
  for (int i=1; i<n; i++) {
    int u, v;
    scanf("%d %d", &u, &v);
    tree.addSide(u, v);
    tree.addSide(v, u);
  }
  tree.build();

  int q;
  scanf("%d", &q);
  for (int i=1; i<=q; i++) {
    int t, a, b, u, v;
    scanf("%d %d %d", &t, &a, &b);
    tree.lca(a, b, u, v);
    if (t==1) {
      tree.change1(a, u), tree.change1(b, v);
    } else if (t==2) {
      tree.change2(a, u), tree.change2(b, v);
      int anc, x;
      anc = (a==b ? a : tree.f[u][0]), x=tree.bigson[anc];
      tree.point.change(1, 1, n, tree.dfn[anc], tree.dfn[anc]);
      tree.side.change(1, 1, n, tree.dfn[anc], tree.dfn[anc]);
      if (x && x!=u && x!=v) {
	tree.side.change(1, 1, n, tree.dfn[x], tree.dfn[x]);
      }
    } else {
      printf("%d\n", tree.solve(a, u)+tree.solve(b, v));
    }
  }

  fclose(stdin);
  fclose(stdout);
  return 0;
}
